package com.googlecode.recycled.lang.jse.api.io;

import com.googlecode.recycled.lang.assertions.Assert;
import com.googlecode.recycled.lang.jse.api.net.Urls;
import org.apache.commons.lang.UnhandledException;

import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

/**
 * Utility class for loading classpath resources.
 */
public class Classpaths {

    // CONSTRUCTION

    /**
     * Protected constructor (since this class is intended to be used only as the utility).
     */
    protected Classpaths() {
    }

    // RESOURCES AS INPUT STREAMS

    public static InputStream asInputStream(@Nullable Class baseClass, String path) {
        try {
            return asUrl(baseClass, path).openStream();
        } catch (IOException e) {
            throw new UnhandledException(e);
        }
    }

    public static InputStream asInputStream(Object context, String path) {
        return asInputStream(context.getClass(), path);
    }

    public static InputStream asInputStream(String path) {
        return asInputStream(null, path);
    }

    // RESOURCES AS URLS

    /**
     * <p>
     * Returns classpath resource as URL. Resources are resolved from the following sources (in order):
     * </p>
     * <ul>
     * <li>from the {@code baseClass} context passed as the param (if passed)</li>
     * <li>from the {@code Classpaths#getClass()} context</li>
     * <li>using the {@code java.lang.Thread#getContextClassLoader()} of the current thread</li>
     * </ul>
     *
     * @param baseClass Class context of the resource. Path of the resource will be
     *                  relative to this class. Optional.
     * @param path      Path of the resource. Relative to the {@code baseClass} (if passed). Cannot be null.
     * @return URL of the classpath resource.
     */
    public static URL asUrl(@Nullable Class baseClass, String path) {
        Assert.notNull(path, "Null path passed.");
        URL url = null;
        if (baseClass != null) {
            url = baseClass.getResource(path);
        }
        if (url == null) {
            url = Classpaths.class.getResource(path);
        }
        if (url == null && Thread.currentThread().getContextClassLoader() != null) {
            url = Thread.currentThread().getContextClassLoader().getResource(path);
        }
        return Assert.notNull(url, path);
    }

    public static URL asUrl(Object context, String path) {
        return asUrl(context.getClass(), path);
    }

    public static URL asUrl(String path) {
        return asUrl(null, path);
    }

    // RESOURCES AS FILES

    public static File asFile(Class baseClass, String path) {
        URL resourceUrl = asUrl(baseClass, path);
        return Assert.notNull(Urls.asFile(resourceUrl));
    }

    public static File asFile(Object context, String path) {
        return asFile(context.getClass(), path);
    }

    public static File asFile(String path) {
        return asFile(null, path);
    }

    // DIRECTORIES OF RESOURCES

    public static File getClassDirectory(Object context) {
        return getClassDirectory(context.getClass());
    }

    public static File getClassDirectory(Class baseClass) {
        return asFile(baseClass, ".");
    }

}
